package cn.bugio.note.auth;

import cn.bugio.note.utils.JwtOperator;
import io.jsonwebtoken.Claims;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Objects;


/**
 * @author Vincent Vic
 * @version 1.0
 * @Description aop
 * @since 2021/3/4
 */

@Aspect
@Component
@Slf4j
public class AuthAspect {

    @Autowired
    private JwtOperator jwtOperator;

    /**
     * 处理加token CheckLogin方法
     *
     * @param point
     * @return
     */
    @Around("@annotation(cn.bugio.note.auth.CheckLogin)")
    public Object checkLogin(ProceedingJoinPoint point) {
        try {
            checkToken();

            return point.proceed();
        } catch (Throwable throwable) {
            throw new SecurityException("Token不合法！");
        }
    }

    private void checkToken() {
        //1.从header里面获取token
        HttpServletRequest request = getRequest();

        String token = request.getHeader("x-token");

        log.info("aop token : {}", token);
        //2.校验token是否合法，不合法，直接抛异常；合法直接放行
        Boolean isValid = jwtOperator.validateToken(token);
        if (!isValid) {
            log.error("Token不合法！");
            throw new SecurityException("Token不合法");
        }

        //3.校验成功，将用户信息设置到request的attribute里面
        Claims claims = jwtOperator.getClaimsFromToken(token);

        request.setAttribute("id", claims.get("id"));
        request.setAttribute("wxNickname", claims.get("wxNickname"));
        request.setAttribute("roles", claims.get("roles"));
        log.info("用户数据 : {}", claims);
    }

    private HttpServletRequest getRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = attributes.getRequest();
        return request;
    }

    /**
     * 处理CheckAuth方法
     *
     * @param point
     * @return
     */
    @Around("@annotation(cn.bugio.note.auth.CheckAuth)")
    public Object checkAuth(ProceedingJoinPoint point) throws Exception {


        try {
            //1.token是否合法
            checkToken();
            //2.验证角色是否匹配
            HttpServletRequest request = getRequest();
            String role = (String) request.getAttribute("roles");

            //对比CheckAuth注解value
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            CheckAuth checkAuth = (CheckAuth) method.getAnnotation(CheckAuth.class);
            if (StringUtils.isNotBlank(checkAuth.value())) {
                if (!Objects.equals(role, checkAuth.value())) {
                    throw new SecurityException("没有权限");
                }
            } else {
                throw new SecurityException("授权字段异常");
            }

            return point.proceed();
        } catch (SecurityException securityException){
            throw securityException;
        } catch (Exception e) {
            throw e;
        } catch (Throwable throwable) {
            throw new Exception(throwable);
        }
    }
}
